<template>
    <div class="my-scroll"
        :class="[isScroll ? 'prohibit' : 'allow']"
        ref="myScroll"
        @scroll.passive="onScroll($event)"
        @touchstart="touchStart($event)"
        @touchmove="touchMove($event)"
        @touchend="touchEnd($event)">
        <div class="scroll-top" :style="{ height: top + 'px' }">
            <div v-if="aspect===2">
                <p v-if="state===6">
                    下拉刷新
                </p>
                <p v-if="state===1">
                    <i><img class="load-img" :src="Load"/></i>
                    <br/>
                    刷新中
                </p>
                <p v-if="state===2">松开刷新</p>
                <p v-if="state===3">
                    <i><img class="load-img" :src="Load"/></i>
                    <br/>
                    刷新完成
                </p>
            </div>
        </div>
        <div class="scroll-list" :style="{ transform: 'translate3d(0, ' + top + 'px, 0)'}">
            <slot></slot>
            <div class="scroll-bottom">
                <div v-if="state===4">加载中</div>
                <div v-if="state===5">加载完成</div>
                <div v-if="state===7">没有更多数据了</div>
            </div>
        </div>
        <!-- 遮罩层-->
        <div class="mask"
              :class= "mask === true ? 'mask-show' : ''"
              @click="Mclose" v-if="showLoading"
              @touchmove.stop.prevent="preventTouchMove">
            <!-- 加载动画开始 -->
            <loadings></loadings>
            <!-- 加载动画结束 -->
        </div>
    </div>
</template>
<script type="text/javascript">
import TWEEN from '@tweenjs/tween.js';
import Load from '@/assets/loading.gif';
import loadings from '@/components/w-loading/loading27.vue';

export default {
    name: 'cuScroll',
    components:{
        loadings,
    },
    props: {
        onRefresh: { // 刷新回调
            type: Function,
            require: true,
        },
        onPull: { // 加载回调
            type: Function,
            require: true,
        },
        getScrollTop: { // 获取滚动条位置
            type: Function,
        },
        isScroll: { // 是否可滑动
            type: Boolean,
            default: false,
        },
        mask: {
            type: Boolean,
            default: false,
        }, // mask: false 无遮罩层 | true 有遮罩层
        hideClick: {
            type: Boolean,
            default: true,
        },// click:true 点击空白无法关闭加载状态 | false 点击空白可关闭加载状态
    },
    data() {
        return {
            Load,
            pages: {
                X: 0,
                Y: 0,
            },
            showLoading: false,
            state: 0,
            scrollPosition: 0,
            myScroll: null,
            myScrollList: null,
            top: 0,
            aspect: 0, // 1:向上 2:向下
            listHeight: 0,
        };
    },
    mounted() {
        this.myScroll = this.$refs.myScroll; // 获取滑条dom
        this.myScrollList = this.myScroll.children[1]; // 获取列表dom
    },
    methods: {
        Mclose(){
            if(this.hideClick){
                this.showLoading = false;
            }
        },
        preventTouchMove(){},
        ScrollTop(top) { // 修改滚动条位置
            this.myScroll.scrollTop = top;
        },
        /*
         * 刷新中：1
         * 松开刷新：2
         * 刷新完成：3
         * 加载中：4
         * 加载完成：5
         * 下拉刷新：6
         * 没有更多：7
         */
        setState(index) { // 修改状态
            this.state = index;
            if (index === 5 || index === 3) {
                setTimeout(() => {
                    this.state = 0;
                    let timer = null;
                    const that = this;
                    cancelAnimationFrame(timer);
                    timer = requestAnimationFrame(function fn() {
                        const oTop = that.top;
                        if (that.top > 0) {
                            that.top = Math.ceil(new TWEEN.Tween({ Y: 0 }).to({ Y: oTop }, 6000).start()) - 15;
                            timer = requestAnimationFrame(fn);
                        } else {
                            cancelAnimationFrame(timer);
                            that.top = 0;
                        }
                    });
                }, 500);
            }
        },
        touchStart(e) { // 触摸事件
            this.pages = {
                X: e.targetTouches[0].pageX,
                Y: e.targetTouches[0].pageY,
            };
        },
        touchMove(e) { // 触摸滑动事件
            this.scrollPosition = this.myScroll.scrollTop; // 获取滚动条位置
            if (this.isScroll && e.targetTouches[0].pageY > this.pages.Y) { // 向下滑动
                this.aspect = 2;
                if (this.myScroll.scrollTop === 0) {
                    const diff = e.targetTouches[0].pageY - this.pages.Y - this.scrollPosition;
                    this.top = diff ** 0.9;
                    const range = (diff / document.body.clientHeight) * 100; // 计算在屏幕上滑动了多少
                    if (range > 20) {
                        this.state = 2;
                    } else if (range < 15) {
                        this.state = 6;
                    }
                    e.preventDefault();
                }
            } else if (this.isScroll && this.state !== 4) { // 向上滑动
                this.aspect = 1;
            }
        },
        touchEnd(e) {
            if ((this.aspect === 2 && this.state === 2) || this.state === 1) { // 上拉处理
                this.top = 100;
                this.state = 1;
                this.topCallback();
            } else if (this.aspect === 2) {
                this.state = 0;
                this.top = 0;
            }
        },
        onScroll(e) {
            const listHeight = this.myScrollList.offsetHeight; // 列表总高度
            const listScrollTop = e.target.scrollTop + this.myScroll.offsetHeight; // 当前滚动条位置

            if (this.state === 0 && listHeight - listScrollTop < 1) {
                this.bottomCallback();
            }

            if (this.getScrollTop) this.getScrollTop(e.target.scrollTop); // 返回X，Y
        },
        topCallback() { // 下拉刷新回调
            this.onRefresh(this.state);
        },
        bottomCallback() { // 上滑加载回调
            if (this.state !== 7) {
                this.state = 4;
                this.onPull(this.state);
            }
        },
    },
};
</script>
<style lang="less" scoped>
    .allow{
        overflow:hidden;
        height: auto;
    }
    .prohibit{
        max-width: 100%;
        max-height: 100%;
        height: 100%;
        overflow:hidden;
        overflow-y: scroll;
        -webkit-overflow-scrolling: touch;
        will-change: transform;
        transition: all 450ms;
        backface-visibility: hidden;
        perspective: 1000;
    }
    .my-scroll{
        position: relative;
        color: #fff;
        .scroll-top{
            text-align: center;
            display:flex;
            position:absolute;
            top:0;
            left:0;
            width:100%;
            overflow: hidden;
            div{
                display:flex;
                height:auto;
                width:100%;
                justify-content: center;
                align-items:center;
                flex-wrap: wrap;
                i{
                    flex:1 0 100%;
                    display:block;
                    height: 0.4rem;
                }
                img{
                    width:0.6rem;
                }
                p{
                    flex:1 0 100%;
                    color: #333;
                    font-size: 26px;
                }
            }
        }
        .scroll-list{
            overflow:hidden;
            min-height: 100%;
        }
        .scroll-bottom{
            text-align: center;
            line-height: 80px;
            color: #999;
            font-size: 26px;
        }
    }
    .load-img{
        width: 100px;
        height: 100px;
    }

    /* 遮罩层 */
    .mask {
        /* pointer-events: none; */
        position: fixed;
        z-index: 99999;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        height: 100vh;
        width: 100vw;
        display: flex;
        flex-direction:column;
        justify-content: center;
        align-items: center;
        flex-wrap: wrap;
    }
    .mask.mask-show{
        background: rgba(7, 17, 27, .3);
    }
    .title{
        color: #fff;
        font-size: 28px;
    }

</style>
